#include <asm/types.h>
#include <arpa/inet.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>

int main(int argc, char ** argv) {

    char buf[16384];

    // Our message will be a header followed by an address payload
    struct {
        struct nlmsghdr nlhdr;
        struct ifaddrmsg addrmsg;
    } msg;

    struct nlmsghdr *retmsg;

    // Set up the netlink socket
    int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);

    // Fill in the message
    // NLM_F_REQUEST means we are asking the kernel for data
    // NLM_F_ROOT means provide all the addresses
    // RTM_GETADDR means we want the addresses of interfaces
    // AF_INET6 means limit the response to ipv6 addresses
    memset(&msg, 0, sizeof(msg));
    msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
    msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
    msg.nlhdr.nlmsg_type = RTM_GETADDR;
    msg.addrmsg.ifa_family = AF_INET6;

    // Send the netlink message
    send(sock, &msg, msg.nlhdr.nlmsg_len, 0);

    int len;

    // Get the netlink reply
    len = recv(sock, buf, sizeof(buf), 0);

    retmsg = (struct nlmsghdr *)buf;

    // Loop through the reply messages (one for each address)
    // Each message has a ifaddrmsg structure in it, which 
    // contains the prefix length as a member.  The ifaddrmsg
    // structure is followed by one or more rtattr structures, 
    // some of which (should) contain raw addresses.
    while NLMSG_OK(retmsg, len) {

        struct ifaddrmsg *retaddr;
        retaddr = (struct ifaddrmsg *)NLMSG_DATA(retmsg);

        struct rtattr *retrta;
        retrta = (struct rtattr *)IFA_RTA(retaddr);

        int attlen;
        attlen = IFA_PAYLOAD(retmsg);

        char pradd[128];

        // Loop through the routing information to look for the 
        // raw address.
        while RTA_OK(retrta, attlen) {
            if (retrta->rta_type == IFA_ADDRESS) {
                inet_ntop(AF_INET6, RTA_DATA(retrta), pradd, sizeof(pradd));
                printf("%s/%u\n", pradd, retaddr->ifa_prefixlen);
            }
            retrta = RTA_NEXT(retrta, attlen);

        }

        retmsg = NLMSG_NEXT(retmsg, len);       
    }

}
